package com.mtw.bbs.fileAdmin.util;

import com.mtw.bbs.fileAdmin.constant.FAConstants;
import com.mtw.bbs.fileAdmin.constant.FileTypeEnum;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.boot.system.ApplicationHome;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;



/**
 * 文件工具类
 */
public class FileUtilz {


    // 常见图片格式
    private final static List<String> imageTypeList = Arrays.asList("png", "jpg", "jpeg", "bmp", "gif", "webp", "psd", "svg", "tif");

    // 常见视频格式
    private final static List<String>  videoTypeList =  Arrays.asList("mp4", "mov", "wmv", "flv", "avi", "avchd", "webm", "mkv");

    public static final String CLASS_PATH = getJarPath();


    /**
     * 获取文件MD5
     *
     * @param filePath 文件路径
     * @return 字符串文件MD5
     * @throws Exception
     */
    public static String getMD5(String filePath) throws Exception {

        File file = new File(filePath);
        return getMD5(file);
    }


    /**
     * 获取文件MD5
     *
     * @param file 文件
     * @return 字符串文件MD5
     * @throws Exception
     */
    public static String getMD5(File file) throws Exception {

        if (file == null || !file.exists()){
            return null;
        }
        return getMD5(new FileInputStream(file));
    }

    /**
     * 获取文件MD5
     *
     * @param fis 文件流
     * @return 字符串文件MD5
     * @throws Exception
     */
    public static String getMD5(FileInputStream fis) throws Exception {

        MessageDigest md = MessageDigest.getInstance("MD5");
        FileChannel channel = fis.getChannel();
        ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);

        while (channel.read(buffer) != -1) {
            buffer.flip();
            md.update(buffer);
            buffer.clear();
        }

        channel.close();
        fis.close();

        byte[] digest = md.digest();
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            sb.append(String.format("%02x", b & 0xff));
        }
        return sb.toString();
    }

    /**
     * 获取文件MD5
     *
     * @param in 流
     * @return 字符串文件MD5
     * @throws Exception
     */
    public static String getMD5(InputStream in) throws Exception {

        MessageDigest md5Digest = null;
        try{
            md5Digest = MessageDigest.getInstance("MD5");
        }
        catch (NoSuchAlgorithmException e){
            e.printStackTrace();
        }
        String checksum = null;
        try{
            checksum = getInputStreamChecksum(md5Digest, in);
        }
        catch (IOException e){
            e.printStackTrace();
        }
        return checksum;
    }


    private static String getInputStreamChecksum(MessageDigest digest, InputStream inputStream) throws IOException{

        InputStream fis = inputStream;
        byte[] byteArray = new byte[1024];
        int bytesCount = 0;
        while ((bytesCount = fis.read(byteArray)) != -1){
            digest.update(byteArray, 0, bytesCount);
        }
        fis.close();
        byte[] bytes = digest.digest();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < bytes.length; i++){
            sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
        }
        return sb.toString();
    }


    /**
     * 用uuid重命名文件
     * @param oldName           旧文件名
     * @return                  新文件名
     */
    public static String renameByUUID(String oldName){

        // 获取文件后缀名
        int indexOfLast = oldName.lastIndexOf(".");
        String suffix = oldName.substring(indexOfLast);
        // 用uuid重命名文件
        String uuid = UUID.randomUUID().toString();
        return  uuid.replaceAll("\\-", "") + suffix;
    }




    /**
     * 生成文件路径
     * @param rename        重命名后的文件名称
     * @param date          日期
     * @return              文件路径
     */
    public static String creatPath(String rename,String date){
        String type = getBusinessFileTypeByName(rename);
        return creatPath(type,rename,date);
    }

    /**
     * 生成文件路径
     * @param rename         重命名后的文件名称
     * @param date           日期
     * @return               文件路径
     */
    public static String creatPath(String rename, Date date){
        String type = getBusinessFileTypeByName(rename);
        return creatPath(type,rename, DateFormatUtils.format(date,"yyyyMMdd"));
    }


    /**
     * 生成文件路径
     * @param type          分类文件夹 @see FileTypeEnum
     * @param rename        重命名后的文件名称
     * @param date          日期
     * @return              文件路径
     */
    public static String creatPath(String type,String rename,String date){

        return  type + File.separator + date + File.separator + rename;
    }


    /**
     * 获取分片文件路径
     * @param md5           文件md5
     * @param date          日期
     */
    public static String creatShardFilePath(String md5 ,String date){
        return date + File.separator + md5 + FAConstants.SEPARATOE;
    }


    /**
     * 获取分片文件路径
     * @param path              文件路径
     * @param fileName          文件名
     * @param index             当前为第几片
     */
    public static String creatShardFilePath(String path,String fileName,Integer index){

        // 获取文件后缀名
        int indexOfLast = fileName.lastIndexOf(".");
        String suffix = fileName.substring(indexOfLast);
        return path + FAConstants.SEPARATOE + index + suffix;
    }


    /**
     * 获取分片文件路径
     * @param oldName       旧文件名
     * @param md5           文件md5
     * @param date          日期
     * @param replace       替换字符
     */
    public static String creatShardFilePath(String oldName,String md5 ,String date,String replace){

        // 获取文件后缀名
        int indexOfLast = oldName.lastIndexOf(".");
        String suffix = oldName.substring(indexOfLast);
        return date + File.separator + md5 + FAConstants.SEPARATOE + replace + suffix;
    }


    /**
     * 根据文件名获取桶下的分类文件夹
     * @param fileName          文件名
     * @return                  文件夹名称
     */
    public static String getBusinessFileTypeByName(String fileName){

        String suffix = getFileFormatByName(fileName);
        if (imageTypeList.contains(suffix.toLowerCase())){
            return FileTypeEnum.IMAGE;
        }
        if (videoTypeList.contains(suffix.toLowerCase())) {
            return FileTypeEnum.VIDEO;
        }
        return FileTypeEnum.OTHER;
    }


    /**
     * 文件是否为视频
     * @param fileName  文件名
     */
    public static boolean fileIsVideo(String fileName){
        String suffix = getFileFormatByName(fileName);
        return videoTypeList.contains(suffix.toLowerCase());
    }



    public static String getJarPath(){
        ApplicationHome h = new ApplicationHome(FileUtilz.class);
        File jarF = h.getSource();
        return jarF.getParentFile().toString();
    }


    /**
     * 根据文件格式获取桶下的分类文件夹
     * @param fileFormat                文件格式
     * @return                          文件夹名称
     */
    public static String getBusinessFileTypeByFormat(String fileFormat){

        if (imageTypeList.contains(fileFormat.toLowerCase())){
            return FileTypeEnum.IMAGE;
        }
        if (videoTypeList.contains(fileFormat.toLowerCase())) {
            return FileTypeEnum.VIDEO;
        }
        return FileTypeEnum.OTHER;
    }



    /**
     * 获取文件格式
     * @param fileName          文件名
     */
    public static String getFileFormatByName(String fileName){

        if (fileName == null){
            return null;
        }
        // 获取文件后缀名
        int indexOfLast = fileName.lastIndexOf(".");
        return fileName.substring(indexOfLast+1);
    }


}
